{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=8, releaselevel='final', serial=0)\n",
      "matplotlib 3.6.3\n",
      "numpy 1.22.3\n",
      "pandas 1.5.2\n",
      "sklearn 1.2.0\n",
      "torch 1.13.1+cu117\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/bin/zsh: /home/ouyanghongyu/anaconda3/envs/pytorch/lib/libtinfo.so.6: no version information available (required by /bin/zsh)\n",
      "--2023-04-24 22:25:16--  https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt\n",
      "正在解析主机 storage.googleapis.com (storage.googleapis.com)... 142.251.43.16, 172.217.160.80, 142.251.42.240, ...\n",
      "正在连接 storage.googleapis.com (storage.googleapis.com)|142.251.43.16|:443... 已连接。\n",
      "已发出 HTTP 请求，正在等待回应... 200 OK\n",
      "长度： 1115394 (1.1M) [text/plain]\n",
      "正在保存至: ‘shakespeare.txt.1’\n",
      "\n",
      "shakespeare.txt.1   100%[===================>]   1.06M  3.15MB/s    用时 0.3s    \n",
      "\n",
      "2023-04-24 22:25:17 (3.15 MB/s) - 已保存 ‘shakespeare.txt.1’ [1115394/1115394])\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!wget https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "length 1115394\n",
      "First Citizen:\n",
      "Before we proceed any further, hear me speak.\n",
      "\n",
      "All:\n",
      "Speak, speak.\n",
      "\n",
      "First Citizen:\n",
      "You\n"
     ]
    }
   ],
   "source": [
    "# https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt\n",
    "#文件已经下载好了\n",
    "with open(\"./shakespeare.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    text = file.read()\n",
    "\n",
    "print(\"length\", len(text))\n",
    "print(text[0:100])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构造字典"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "65\n",
      "['\\n', ' ', '!', '$', '&', \"'\", ',', '-', '.', '3', ':', ';', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']\n"
     ]
    }
   ],
   "source": [
    "# 1. generate vocab\n",
    "# 2. build mapping char->id\n",
    "# 3. data -> id_data  把数据都转为id\n",
    "# 4. a b c d [EOS] -> [BOS] b c d  预测下一个字符生成的模型，也就是输入是a，输出就是b\n",
    "\n",
    "#去重，留下独立字符，并排序\n",
    "vocab = sorted(set(text))\n",
    "print(len(vocab))\n",
    "print(vocab)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 how\n",
      "1 are\n",
      "2 you\n"
     ]
    }
   ],
   "source": [
    "for idx,char in enumerate(['how','are','you']):\n",
    "    print(idx,char)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'\\n': 0, ' ': 1, '!': 2, '$': 3, '&': 4, \"'\": 5, ',': 6, '-': 7, '.': 8, '3': 9, ':': 10, ';': 11, '?': 12, 'A': 13, 'B': 14, 'C': 15, 'D': 16, 'E': 17, 'F': 18, 'G': 19, 'H': 20, 'I': 21, 'J': 22, 'K': 23, 'L': 24, 'M': 25, 'N': 26, 'O': 27, 'P': 28, 'Q': 29, 'R': 30, 'S': 31, 'T': 32, 'U': 33, 'V': 34, 'W': 35, 'X': 36, 'Y': 37, 'Z': 38, 'a': 39, 'b': 40, 'c': 41, 'd': 42, 'e': 43, 'f': 44, 'g': 45, 'h': 46, 'i': 47, 'j': 48, 'k': 49, 'l': 50, 'm': 51, 'n': 52, 'o': 53, 'p': 54, 'q': 55, 'r': 56, 's': 57, 't': 58, 'u': 59, 'v': 60, 'w': 61, 'x': 62, 'y': 63, 'z': 64}\n"
     ]
    }
   ],
   "source": [
    "#每个字符都编好号，enumerate对每一个位置编号，生成的是列表中是元组，下面字典生成式\n",
    "char2idx = {char:idx for idx, char in enumerate(vocab)}\n",
    "print(char2idx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['\\n' ' ' '!' '$' '&' \"'\" ',' '-' '.' '3' ':' ';' '?' 'A' 'B' 'C' 'D' 'E'\n",
      " 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W'\n",
      " 'X' 'Y' 'Z' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'\n",
      " 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z']\n"
     ]
    }
   ],
   "source": [
    "# 把vocab从列表变为ndarray\n",
    "idx2char = np.array(vocab)\n",
    "print(idx2char)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1115394,)\n",
      "1115394\n",
      "[18 47 56 57 58  1 15 47 58 47]\n",
      "First Citi\n"
     ]
    }
   ],
   "source": [
    "#把字符都转换为id\n",
    "text_as_int = np.array([char2idx[c] for c in text])\n",
    "print(text_as_int.shape)\n",
    "print(len(text_as_int))\n",
    "print(text_as_int[0:10])\n",
    "print(text[0:10])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 把莎士比亚文集分成一个一个的样本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class CharDataset(Dataset):\n",
    "    def __init__(self, text_as_int, seq_length):\n",
    "        self.sub_len = seq_length + 1\n",
    "        self.text_as_int = text_as_int\n",
    "        self.num_seq = len(text_as_int) // self.sub_len\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        return self.text_as_int[index * self.sub_len: (index + 1) * self.sub_len]\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.num_seq\n",
    "    \n",
    "def collat_fct(batch):\n",
    "    src_list = []\n",
    "    trg_list = []\n",
    "    for part in batch:\n",
    "        src_list.append(part[:-1])\n",
    "        trg_list.append(part[1:])\n",
    "        \n",
    "    src_list = np.array(src_list)\n",
    "    trg_list = np.array(trg_list)\n",
    "    return torch.Tensor(src_list).to(dtype=torch.int64), torch.Tensor(trg_list).to(dtype=torch.int64)\n",
    "        \n",
    "\n",
    "train_ds = CharDataset(text_as_int, 100)\n",
    "train_dl = DataLoader(train_ds, batch_size=64, shuffle=True, collate_fn=collat_fct)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层单向 LSTM ===================================\n",
      "            embedding.weight            paramerters num: 16640\n",
      "           lstm.weight_ih_l0            paramerters num: 1048576\n",
      "           lstm.weight_hh_l0            paramerters num: 4194304\n",
      "            lstm.bias_ih_l0             paramerters num: 4096\n",
      "            lstm.bias_hh_l0             paramerters num: 4096\n",
      "               fc.weight                paramerters num: 66560\n",
      "                fc.bias                 paramerters num: 65\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 128, 65])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class CharLSTM(nn.Module):\n",
    "    def __init__(self, vocab_size, embedding_dim=256, hidden_dim=1024):\n",
    "        super(CharLSTM, self).__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)\n",
    "        self.fc = nn.Linear(hidden_dim, vocab_size)\n",
    "        \n",
    "    def forward(self, x, hidden=None):\n",
    "        x = self.embedding(x)\n",
    "        output, hidden = self.lstm(x, hidden)\n",
    "        x = self.fc(output)\n",
    "        return x, hidden\n",
    "    \n",
    "    \n",
    "vocab_size = len(vocab)\n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 100))\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层单向 LSTM \"))       \n",
    "for key, value in CharLSTM(vocab_size).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "    \n",
    "CharLSTM(vocab_size)(sample_inputs)[0].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [
    {
     "data": {
      "text/plain": "1048576"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "4 * 1024*256"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-13T02:36:48.216578Z",
     "start_time": "2023-12-13T02:36:48.192464200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "data": {
      "text/plain": "4194304"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "4 * 1024*1024"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-13T02:37:02.308627800Z",
     "start_time": "2023-12-13T02:37:02.296635500Z"
    }
   }
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2169a1eb0f3c4e739e577ffb84c23cde",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/17300 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=None,\n",
    "    stateful=False      # 想用stateful，batch里的数据就必须连续，不能打乱\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    hidden = None\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits, hidden = model(datas, hidden=hidden if stateful else None)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits.reshape(-1, vocab_size), labels.reshape(-1))\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    " \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"step\": global_step\n",
    "                })\n",
    "   \n",
    "                # 保存模型权重 save model checkpoint\n",
    "                if save_ckpt_callback is not None:\n",
    "                    save_ckpt_callback(global_step, model.state_dict(), metric=-loss)\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 100\n",
    "\n",
    "model = CharLSTM(vocab_size=vocab_size)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 \n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "\n",
    "# save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/text_generation_lstm\", save_step=1000, save_best_only=True)\n",
    "\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAikAAAGdCAYAAADXIOPgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAABaM0lEQVR4nO3dd3hUVf4G8HcmmUzqpBDSC4HQQygBISBF6aCC7qIiK+oqNtjVxba4/lR0FXYt6FoQK66KKCroIi2UUENJIJBQYkJCAqTXSZ1MZs7vj5m5yZAETIG5Yd7P8/Akc+feO2e+uWTenHPuvQohhAARERGRzCht3QAiIiKiljCkEBERkSwxpBAREZEsMaQQERGRLDGkEBERkSwxpBAREZEsMaQQERGRLDGkEBERkSw52roBv4fRaERubi48PDygUChs3RwiIiL6HYQQqKysRFBQEJTKtveLdImQkpubi9DQUFs3g4iIiNrh/PnzCAkJafN2XSKkeHh4ADC9SY1G02n71ev12LZtG6ZMmQKVStVp++1qWAfWAGANLFgH1gBgDSw6WgetVovQ0FDpc7ytukRIsQzxaDSaTg8prq6u0Gg0dn8Q2nsdWAPWwIJ1YA0A1sCis+rQ3qkanDhLREREssSQQkRERLLEkEJERESyxJBCREREssSQQkRERLLEkEJERESyxJBCREREssSQQkRERLLEkEJERESyxJBCREREssSQQkRERLLEkEJERESyZNch5YsD2fgxS4m0/EpbN4WIiIguYdchZVNqPvbkK3G+rNbWTSEiIqJL2HVIUZpvHW0UwsYtISIiokvZeUgxfWVGISIikh+7DikK9qQQERHJll2HFPakEBERyZedhxT2pBAREcmVXYcUc0aBkRmFiIhIduw6pFh6UgR7UoiIiGTHzkOK6St7UoiIiOTHrkMKz+4hIiKSL7sOKexJISIikq8OhZTly5dDoVDgySefvOx669atQ79+/eDs7IxBgwZh06ZNHXnZTsM5KURERPLV7pBy5MgRrFq1CtHR0Zdd78CBA5g7dy4efPBBHDt2DLNnz8bs2bORmpra3pfuNI2nINu4IURERNRMu0JKVVUV5s2bh08++QTe3t6XXffdd9/FtGnT8Mwzz6B///549dVXMWzYMLz//vvtanBnajwFmSmFiIhIbhzbs9HChQsxc+ZMTJo0Cf/8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dKZaWFiYeO6556yWX6/HQWVlpTh27Jg4duyYACDefvttcezYMemsleXLlwsvLy/x888/ixMnTohZs2a1eAry0KFDxaFDh8S+fftE7969rU47LS8vF/7+/uLee+8VqampYu3atcLV1bXZKZeOjo7izTffFKdPnxYvvfTSNT0F+XJ1qK+vF7fddpsICQkRycnJVr8nLGdoHDhwQKxYsUIkJyeLs2fPiq+//lp0795dzJ8/v8vU4XI1qKysFE8//bRISEgQWVlZYvv27WLYsGGid+/eoq6uTtpHVz8WrvT/QQjTKcSurq5i5cqVzbaX23FgtyFFCCHee+89ERYWJpycnMQNN9wgDh48aOsmtQuAFv998cUXQgghcnJyxLhx44SPj49Qq9UiMjJSPPPMM1bXxxBCiHPnzonp06cLFxcX4evrK5566imh1+ut1tm1a5cYMmSIcHJyEj179pReQw7uuusuERgYKJycnERwcLC46667REZGhvR8bW2tePzxx4W3t7dwdXUVt99+u8jLy7PaR1evgRBCbN26VQAQaWlpVsuv1+Ng165dLR7/9913nxDCdBry//3f/wl/f3+hVqvFxIkTm9WmpKREzJ07V7i7uwuNRiMeeOABUVlZabXO8ePHxY033ijUarUIDg4Wy5cvb9aW77//XvTp00c4OTmJgQMHil9//fWqve9LXa4OWVlZrf6esFxDJykpSYwcOVJ4enoKZ2dn0b9/f/H6669bfYALIe86XK4GNTU1YsqUKaJ79+5CpVKJ8PBwsWDBgmZ/mHb1Y+FK/x+EEGLVqlXCxcVFlJeXN9tebseBQggh2tb3QkRERHT12eWcFCIiIpI/hhQiIiKSJYYUIiIikiWGFCIiIpIlhhQiIiKSJYYUIiIikiWGFCIiIpIlhhQiIiKSJYYUIiIikiWGFCIiIpIlhhQiIiKSJYYUIiIikqX/B4yzxTrHFLzMAAAAAElFTkSuQmCC",
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       "  \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"398.801786pt\" height=\"297.190125pt\" viewBox=\"0 0 398.801786 297.190125\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
       " <metadata>\n",
       "  <rdf:RDF xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n",
       "   <cc:Work>\n",
       "    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n",
       "    <dc:date>2023-04-24T22:29:02.292802</dc:date>\n",
       "    <dc:format>image/svg+xml</dc:format>\n",
       "    <dc:creator>\n",
       "     <cc:Agent>\n",
       "      <dc:title>Matplotlib v3.6.3, https://matplotlib.org/</dc:title>\n",
       "     </cc:Agent>\n",
       "    </dc:creator>\n",
       "   </cc:Work>\n",
       "  </rdf:RDF>\n",
       " </metadata>\n",
       " <defs>\n",
       "  <style type=\"text/css\">*{stroke-linejoin: round; stroke-linecap: butt}</style>\n",
       " </defs>\n",
       " <g id=\"figure_1\">\n",
       "  <g id=\"patch_1\">\n",
       "   <path d=\"M 0 297.190125 \n",
       "L 398.801786 297.190125 \n",
       "L 398.801786 0 \n",
       "L 0 0 \n",
       "z\n",
       "\" style=\"fill: #ffffff\"/>\n",
       "  </g>\n",
       "  <g id=\"axes_1\">\n",
       "   <g id=\"patch_2\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 387.223125 273.312 \n",
       "L 387.223125 7.2 \n",
       "L 30.103125 7.2 \n",
       "z\n",
       "\" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_1\">\n",
       "    <g id=\"xtick_1\">\n",
       "     <g id=\"line2d_1\">\n",
       "      <path d=\"M 46.335852 273.312 \n",
       "L 46.335852 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_2\">\n",
       "      <defs>\n",
       "       <path id=\"m8718f4b3e9\" d=\"M 0 0 \n",
       "L 0 3.5 \n",
       "\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"46.335852\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_1\">\n",
       "      <!-- 0 -->\n",
       "      <g transform=\"translate(43.154602 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-30\" d=\"M 2034 4250 \n",
       "Q 1547 4250 1301 3770 \n",
       "Q 1056 3291 1056 2328 \n",
       "Q 1056 1369 1301 889 \n",
       "Q 1547 409 2034 409 \n",
       "Q 2525 409 2770 889 \n",
       "Q 3016 1369 3016 2328 \n",
       "Q 3016 3291 2770 3770 \n",
       "Q 2525 4250 2034 4250 \n",
       "z\n",
       "M 2034 4750 \n",
       "Q 2819 4750 3233 4129 \n",
       "Q 3647 3509 3647 2328 \n",
       "Q 3647 1150 3233 529 \n",
       "Q 2819 -91 2034 -91 \n",
       "Q 1250 -91 836 529 \n",
       "Q 422 1150 422 2328 \n",
       "Q 422 3509 836 4129 \n",
       "Q 1250 4750 2034 4750 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-30\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_2\">\n",
       "     <g id=\"line2d_3\">\n",
       "      <path d=\"M 93.387236 273.312 \n",
       "L 93.387236 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_4\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"93.387236\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_2\">\n",
       "      <!-- 2500 -->\n",
       "      <g transform=\"translate(80.662236 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-32\" d=\"M 1228 531 \n",
       "L 3431 531 \n",
       "L 3431 0 \n",
       "L 469 0 \n",
       "L 469 531 \n",
       "Q 828 903 1448 1529 \n",
       "Q 2069 2156 2228 2338 \n",
       "Q 2531 2678 2651 2914 \n",
       "Q 2772 3150 2772 3378 \n",
       "Q 2772 3750 2511 3984 \n",
       "Q 2250 4219 1831 4219 \n",
       "Q 1534 4219 1204 4116 \n",
       "Q 875 4013 500 3803 \n",
       "L 500 4441 \n",
       "Q 881 4594 1212 4672 \n",
       "Q 1544 4750 1819 4750 \n",
       "Q 2544 4750 2975 4387 \n",
       "Q 3406 4025 3406 3419 \n",
       "Q 3406 3131 3298 2873 \n",
       "Q 3191 2616 2906 2266 \n",
       "Q 2828 2175 2409 1742 \n",
       "Q 1991 1309 1228 531 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "        <path id=\"DejaVuSans-35\" d=\"M 691 4666 \n",
       "L 3169 4666 \n",
       "L 3169 4134 \n",
       "L 1269 4134 \n",
       "L 1269 2991 \n",
       "Q 1406 3038 1543 3061 \n",
       "Q 1681 3084 1819 3084 \n",
       "Q 2600 3084 3056 2656 \n",
       "Q 3513 2228 3513 1497 \n",
       "Q 3513 744 3044 326 \n",
       "Q 2575 -91 1722 -91 \n",
       "Q 1428 -91 1123 -41 \n",
       "Q 819 9 494 109 \n",
       "L 494 744 \n",
       "Q 775 591 1075 516 \n",
       "Q 1375 441 1709 441 \n",
       "Q 2250 441 2565 725 \n",
       "Q 2881 1009 2881 1497 \n",
       "Q 2881 1984 2565 2268 \n",
       "Q 2250 2553 1709 2553 \n",
       "Q 1456 2553 1204 2497 \n",
       "Q 953 2441 691 2322 \n",
       "L 691 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_3\">\n",
       "     <g id=\"line2d_5\">\n",
       "      <path d=\"M 140.438619 273.312 \n",
       "L 140.438619 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_6\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"140.438619\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_3\">\n",
       "      <!-- 5000 -->\n",
       "      <g transform=\"translate(127.713619 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-35\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_4\">\n",
       "     <g id=\"line2d_7\">\n",
       "      <path d=\"M 187.490002 273.312 \n",
       "L 187.490002 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_8\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"187.490002\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_4\">\n",
       "      <!-- 7500 -->\n",
       "      <g transform=\"translate(174.765002 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-37\" d=\"M 525 4666 \n",
       "L 3525 4666 \n",
       "L 3525 4397 \n",
       "L 1831 0 \n",
       "L 1172 0 \n",
       "L 2766 4134 \n",
       "L 525 4134 \n",
       "L 525 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-37\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_5\">\n",
       "     <g id=\"line2d_9\">\n",
       "      <path d=\"M 234.541386 273.312 \n",
       "L 234.541386 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_10\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"234.541386\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_5\">\n",
       "      <!-- 10000 -->\n",
       "      <g transform=\"translate(218.635136 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-31\" d=\"M 794 531 \n",
       "L 1825 531 \n",
       "L 1825 4091 \n",
       "L 703 3866 \n",
       "L 703 4441 \n",
       "L 1819 4666 \n",
       "L 2450 4666 \n",
       "L 2450 531 \n",
       "L 3481 531 \n",
       "L 3481 0 \n",
       "L 794 0 \n",
       "L 794 531 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_6\">\n",
       "     <g id=\"line2d_11\">\n",
       "      <path d=\"M 281.592769 273.312 \n",
       "L 281.592769 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_12\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"281.592769\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_6\">\n",
       "      <!-- 12500 -->\n",
       "      <g transform=\"translate(265.686519 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-32\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_7\">\n",
       "     <g id=\"line2d_13\">\n",
       "      <path d=\"M 328.644153 273.312 \n",
       "L 328.644153 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_14\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"328.644153\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_7\">\n",
       "      <!-- 15000 -->\n",
       "      <g transform=\"translate(312.737903 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_8\">\n",
       "     <g id=\"line2d_15\">\n",
       "      <path d=\"M 375.695536 273.312 \n",
       "L 375.695536 7.2 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_16\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8718f4b3e9\" x=\"375.695536\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_8\">\n",
       "      <!-- 17500 -->\n",
       "      <g transform=\"translate(359.789286 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-37\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_2\">\n",
       "    <g id=\"ytick_1\">\n",
       "     <g id=\"line2d_17\">\n",
       "      <path d=\"M 30.103125 246.801283 \n",
       "L 387.223125 246.801283 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_18\">\n",
       "      <defs>\n",
       "       <path id=\"m8607c06f96\" d=\"M 0 0 \n",
       "L -3.5 0 \n",
       "\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"246.801283\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_9\">\n",
       "      <!-- 0.5 -->\n",
       "      <g transform=\"translate(7.2 250.600501) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-2e\" d=\"M 684 794 \n",
       "L 1344 794 \n",
       "L 1344 0 \n",
       "L 684 0 \n",
       "L 684 794 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-30\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_2\">\n",
       "     <g id=\"line2d_19\">\n",
       "      <path d=\"M 30.103125 215.834913 \n",
       "L 387.223125 215.834913 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_20\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"215.834913\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_10\">\n",
       "      <!-- 1.0 -->\n",
       "      <g transform=\"translate(7.2 219.634132) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_3\">\n",
       "     <g id=\"line2d_21\">\n",
       "      <path d=\"M 30.103125 184.868544 \n",
       "L 387.223125 184.868544 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_22\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"184.868544\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_11\">\n",
       "      <!-- 1.5 -->\n",
       "      <g transform=\"translate(7.2 188.667763) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_4\">\n",
       "     <g id=\"line2d_23\">\n",
       "      <path d=\"M 30.103125 153.902175 \n",
       "L 387.223125 153.902175 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_24\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"153.902175\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_12\">\n",
       "      <!-- 2.0 -->\n",
       "      <g transform=\"translate(7.2 157.701393) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_5\">\n",
       "     <g id=\"line2d_25\">\n",
       "      <path d=\"M 30.103125 122.935805 \n",
       "L 387.223125 122.935805 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_26\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"122.935805\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_13\">\n",
       "      <!-- 2.5 -->\n",
       "      <g transform=\"translate(7.2 126.735024) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_6\">\n",
       "     <g id=\"line2d_27\">\n",
       "      <path d=\"M 30.103125 91.969436 \n",
       "L 387.223125 91.969436 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_28\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"91.969436\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_14\">\n",
       "      <!-- 3.0 -->\n",
       "      <g transform=\"translate(7.2 95.768655) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-33\" d=\"M 2597 2516 \n",
       "Q 3050 2419 3304 2112 \n",
       "Q 3559 1806 3559 1356 \n",
       "Q 3559 666 3084 287 \n",
       "Q 2609 -91 1734 -91 \n",
       "Q 1441 -91 1130 -33 \n",
       "Q 819 25 488 141 \n",
       "L 488 750 \n",
       "Q 750 597 1062 519 \n",
       "Q 1375 441 1716 441 \n",
       "Q 2309 441 2620 675 \n",
       "Q 2931 909 2931 1356 \n",
       "Q 2931 1769 2642 2001 \n",
       "Q 2353 2234 1838 2234 \n",
       "L 1294 2234 \n",
       "L 1294 2753 \n",
       "L 1863 2753 \n",
       "Q 2328 2753 2575 2939 \n",
       "Q 2822 3125 2822 3475 \n",
       "Q 2822 3834 2567 4026 \n",
       "Q 2313 4219 1838 4219 \n",
       "Q 1578 4219 1281 4162 \n",
       "Q 984 4106 628 3988 \n",
       "L 628 4550 \n",
       "Q 988 4650 1302 4700 \n",
       "Q 1616 4750 1894 4750 \n",
       "Q 2613 4750 3031 4423 \n",
       "Q 3450 4097 3450 3541 \n",
       "Q 3450 3153 3228 2886 \n",
       "Q 3006 2619 2597 2516 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-33\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_7\">\n",
       "     <g id=\"line2d_29\">\n",
       "      <path d=\"M 30.103125 61.003067 \n",
       "L 387.223125 61.003067 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_30\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"61.003067\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_15\">\n",
       "      <!-- 3.5 -->\n",
       "      <g transform=\"translate(7.2 64.802285) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-33\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_8\">\n",
       "     <g id=\"line2d_31\">\n",
       "      <path d=\"M 30.103125 30.036697 \n",
       "L 387.223125 30.036697 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_32\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m8607c06f96\" x=\"30.103125\" y=\"30.036697\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_16\">\n",
       "      <!-- 4.0 -->\n",
       "      <g transform=\"translate(7.2 33.835916) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-34\" d=\"M 2419 4116 \n",
       "L 825 1625 \n",
       "L 2419 1625 \n",
       "L 2419 4116 \n",
       "z\n",
       "M 2253 4666 \n",
       "L 3047 4666 \n",
       "L 3047 1625 \n",
       "L 3713 1625 \n",
       "L 3713 1100 \n",
       "L 3047 1100 \n",
       "L 3047 0 \n",
       "L 2419 0 \n",
       "L 2419 1100 \n",
       "L 313 1100 \n",
       "L 313 1709 \n",
       "L 2253 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-34\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_33\">\n",
       "    <path d=\"M 46.335852 19.296 \n",
       "L 47.27688 143.958335 \n",
       "L 48.217908 162.025458 \n",
       "L 50.099963 179.11911 \n",
       "L 51.040991 182.617871 \n",
       "L 51.982018 183.712609 \n",
       "L 52.923046 190.986225 \n",
       "L 53.864074 191.668721 \n",
       "L 54.805101 190.73722 \n",
       "L 55.746129 191.058955 \n",
       "L 56.687157 194.235332 \n",
       "L 57.628184 195.555863 \n",
       "L 58.569212 192.516476 \n",
       "L 59.51024 196.44452 \n",
       "L 60.451267 197.556474 \n",
       "L 61.392295 197.293892 \n",
       "L 62.333323 200.043741 \n",
       "L 63.27435 199.386754 \n",
       "L 64.215378 199.166631 \n",
       "L 65.156406 203.282209 \n",
       "L 66.097433 202.990302 \n",
       "L 67.038461 202.117193 \n",
       "L 67.979489 202.083667 \n",
       "L 68.920516 201.002152 \n",
       "L 69.861544 204.279034 \n",
       "L 70.802572 204.845661 \n",
       "L 71.743599 203.736416 \n",
       "L 72.684627 209.225246 \n",
       "L 73.625655 206.835243 \n",
       "L 74.566682 205.123297 \n",
       "L 75.50771 206.450827 \n",
       "L 76.448738 209.654698 \n",
       "L 77.389765 207.973628 \n",
       "L 78.330793 208.07208 \n",
       "L 79.271821 213.732055 \n",
       "L 80.212848 211.067878 \n",
       "L 81.153876 211.024259 \n",
       "L 82.094904 210.680701 \n",
       "L 83.035931 213.671529 \n",
       "L 83.976959 212.173431 \n",
       "L 84.917987 213.435991 \n",
       "L 85.859014 217.0346 \n",
       "L 86.800042 216.457714 \n",
       "L 87.74107 216.95112 \n",
       "L 88.682097 222.029481 \n",
       "L 89.623125 219.347813 \n",
       "L 90.564153 217.741189 \n",
       "L 91.50518 217.950806 \n",
       "L 92.446208 224.411799 \n",
       "L 93.387236 221.671079 \n",
       "L 94.328263 220.761306 \n",
       "L 95.269291 225.00637 \n",
       "L 96.210319 224.481582 \n",
       "L 97.151346 223.334079 \n",
       "L 98.092374 223.659985 \n",
       "L 99.033402 229.022991 \n",
       "L 99.974429 226.96467 \n",
       "L 100.915457 224.496297 \n",
       "L 101.856485 232.81782 \n",
       "L 102.797512 229.718894 \n",
       "L 103.73854 228.997841 \n",
       "L 104.679568 228.659004 \n",
       "L 105.620595 235.426463 \n",
       "L 106.561623 232.363846 \n",
       "L 107.502651 231.822132 \n",
       "L 108.443678 237.815001 \n",
       "L 109.384706 236.303411 \n",
       "L 110.325734 235.583185 \n",
       "L 111.266761 232.090769 \n",
       "L 112.207789 239.278008 \n",
       "L 113.148817 237.98417 \n",
       "L 114.089844 236.106374 \n",
       "L 115.030872 243.619693 \n",
       "L 115.9719 239.9323 \n",
       "L 116.912927 239.122885 \n",
       "L 117.853955 237.303506 \n",
       "L 118.794983 243.225565 \n",
       "L 119.73601 242.627468 \n",
       "L 120.677038 239.032366 \n",
       "L 121.618066 245.680103 \n",
       "L 122.559093 245.222422 \n",
       "L 123.500121 242.444732 \n",
       "L 124.441149 240.290821 \n",
       "L 125.382176 246.44243 \n",
       "L 126.323204 245.361584 \n",
       "L 127.264232 242.843305 \n",
       "L 128.205259 248.399121 \n",
       "L 129.146287 247.72621 \n",
       "L 130.087315 245.03646 \n",
       "L 131.028342 250.097421 \n",
       "L 131.96937 249.35665 \n",
       "L 132.910398 248.280403 \n",
       "L 133.851425 246.682365 \n",
       "L 134.792453 251.280637 \n",
       "L 135.733481 249.739925 \n",
       "L 136.674508 249.370528 \n",
       "L 137.615536 251.541614 \n",
       "L 138.556564 252.25485 \n",
       "L 140.438619 248.917535 \n",
       "L 141.379647 253.596976 \n",
       "L 142.320674 251.877826 \n",
       "L 143.261702 249.872861 \n",
       "L 144.20273 254.141607 \n",
       "L 145.143757 254.403889 \n",
       "L 146.084785 251.56507 \n",
       "L 147.025813 251.128002 \n",
       "L 147.96684 256.249158 \n",
       "L 148.907868 254.102961 \n",
       "L 149.848896 251.226133 \n",
       "L 150.789923 255.814711 \n",
       "L 151.730951 255.251628 \n",
       "L 152.671979 253.64983 \n",
       "L 153.613006 252.716047 \n",
       "L 154.554034 256.46197 \n",
       "L 155.495062 255.560392 \n",
       "L 156.436089 253.67132 \n",
       "L 157.377117 257.796714 \n",
       "L 158.318145 255.138901 \n",
       "L 159.259172 255.099443 \n",
       "L 160.2002 252.790532 \n",
       "L 161.141228 256.304162 \n",
       "L 162.082255 256.389127 \n",
       "L 163.023283 254.238117 \n",
       "L 163.964311 257.389441 \n",
       "L 164.905338 257.371323 \n",
       "L 165.846366 256.26854 \n",
       "L 166.787394 253.006644 \n",
       "L 167.728421 257.495327 \n",
       "L 168.669449 255.973917 \n",
       "L 169.610477 255.436418 \n",
       "L 170.551504 258.881461 \n",
       "L 172.43356 256.294356 \n",
       "L 173.374587 258.735136 \n",
       "L 174.315615 259.633083 \n",
       "L 175.256643 257.841012 \n",
       "L 176.19767 256.790493 \n",
       "L 177.138698 259.780153 \n",
       "L 178.079726 258.239393 \n",
       "L 179.020753 257.713684 \n",
       "L 179.961781 260.182467 \n",
       "L 180.902809 258.710809 \n",
       "L 181.843836 258.257438 \n",
       "L 182.784864 255.413702 \n",
       "L 183.725892 259.767628 \n",
       "L 184.666919 259.293865 \n",
       "L 185.607947 257.294483 \n",
       "L 186.548975 259.286368 \n",
       "L 187.490002 259.644189 \n",
       "L 189.372058 255.694624 \n",
       "L 190.313085 259.80293 \n",
       "L 191.254113 259.009073 \n",
       "L 192.195141 256.227064 \n",
       "L 193.136168 259.330998 \n",
       "L 194.077196 259.133672 \n",
       "L 195.018224 257.850669 \n",
       "L 195.959251 255.547969 \n",
       "L 196.900279 259.395272 \n",
       "L 197.841307 259.327373 \n",
       "L 198.782334 256.846561 \n",
       "L 199.723362 260.281246 \n",
       "L 200.66439 259.803664 \n",
       "L 202.546445 256.486634 \n",
       "L 203.487473 259.999933 \n",
       "L 204.4285 259.982391 \n",
       "L 205.369528 257.996796 \n",
       "L 206.310556 260.401863 \n",
       "L 207.251583 259.539847 \n",
       "L 208.192611 258.886245 \n",
       "L 209.133639 259.9858 \n",
       "L 210.074667 260.595963 \n",
       "L 211.015694 259.895331 \n",
       "L 211.956722 258.002828 \n",
       "L 212.89775 260.835076 \n",
       "L 214.779805 257.953853 \n",
       "L 215.720833 261.216 \n",
       "L 216.66186 259.216223 \n",
       "L 217.602888 259.090963 \n",
       "L 218.543916 257.714933 \n",
       "L 219.484943 260.130687 \n",
       "L 220.425971 259.982928 \n",
       "L 221.366999 258.435058 \n",
       "L 222.308026 260.933812 \n",
       "L 223.249054 260.364608 \n",
       "L 224.190082 258.586975 \n",
       "L 225.131109 257.460588 \n",
       "L 226.072137 260.459385 \n",
       "L 227.013165 259.907481 \n",
       "L 227.954192 257.891107 \n",
       "L 228.89522 259.617927 \n",
       "L 229.836248 260.525269 \n",
       "L 231.718303 257.226222 \n",
       "L 232.659331 260.606027 \n",
       "L 233.600358 259.156341 \n",
       "L 234.541386 256.612549 \n",
       "L 235.482414 260.487893 \n",
       "L 236.423441 259.817736 \n",
       "L 237.364469 258.58431 \n",
       "L 238.305497 256.491298 \n",
       "L 239.246524 259.959673 \n",
       "L 240.187552 259.17638 \n",
       "L 241.12858 257.637608 \n",
       "L 242.069607 260.436177 \n",
       "L 243.951663 258.070932 \n",
       "L 244.89269 257.338622 \n",
       "L 245.833718 260.345403 \n",
       "L 246.774746 258.578043 \n",
       "L 247.715773 257.597219 \n",
       "L 248.656801 259.931609 \n",
       "L 249.597829 259.603326 \n",
       "L 250.538856 258.834553 \n",
       "L 251.479884 260.172875 \n",
       "L 252.420912 260.602626 \n",
       "L 253.361939 258.546526 \n",
       "L 254.302967 256.984319 \n",
       "L 255.243995 260.675837 \n",
       "L 256.185022 259.594282 \n",
       "L 257.12605 257.997283 \n",
       "L 259.008105 259.87692 \n",
       "L 259.949133 257.750578 \n",
       "L 260.890161 256.259034 \n",
       "L 261.831188 260.336023 \n",
       "L 262.772216 257.876932 \n",
       "L 263.713244 256.316677 \n",
       "L 264.654271 259.446829 \n",
       "L 265.595299 260.288584 \n",
       "L 267.477354 256.007021 \n",
       "L 268.418382 260.351168 \n",
       "L 269.35941 259.83597 \n",
       "L 270.300437 258.869235 \n",
       "L 271.241465 259.950903 \n",
       "L 272.182493 259.952732 \n",
       "L 273.12352 258.192561 \n",
       "L 274.064548 257.357698 \n",
       "L 275.005576 259.763966 \n",
       "L 275.946603 257.992761 \n",
       "L 276.887631 257.194211 \n",
       "L 277.828659 259.613045 \n",
       "L 278.769686 259.639392 \n",
       "L 279.710714 257.920002 \n",
       "L 280.651742 255.73391 \n",
       "L 281.592769 259.987016 \n",
       "L 282.533797 258.459798 \n",
       "L 283.474825 257.822235 \n",
       "L 284.415852 258.151522 \n",
       "L 285.35688 258.132521 \n",
       "L 286.297908 257.533864 \n",
       "L 287.238935 255.873681 \n",
       "L 288.179963 258.780095 \n",
       "L 289.120991 257.020411 \n",
       "L 290.062018 255.499344 \n",
       "L 291.003046 258.665908 \n",
       "L 291.944074 258.211863 \n",
       "L 292.885101 257.034475 \n",
       "L 293.826129 259.630347 \n",
       "L 294.767157 257.825829 \n",
       "L 295.708184 257.58881 \n",
       "L 296.649212 255.483973 \n",
       "L 297.59024 258.131175 \n",
       "L 298.531267 258.269971 \n",
       "L 299.472295 256.065182 \n",
       "L 300.413323 259.054639 \n",
       "L 301.35435 259.178361 \n",
       "L 302.295378 257.166677 \n",
       "L 303.236406 256.320462 \n",
       "L 304.177433 258.997545 \n",
       "L 305.118461 258.283519 \n",
       "L 306.059489 256.634472 \n",
       "L 307.000516 258.56899 \n",
       "L 307.941544 258.824348 \n",
       "L 308.882572 257.910709 \n",
       "L 309.823599 255.457454 \n",
       "L 310.764627 259.350087 \n",
       "L 311.705655 256.752792 \n",
       "L 312.646682 256.385772 \n",
       "L 313.58771 257.884675 \n",
       "L 314.528738 258.260923 \n",
       "L 315.469765 256.384068 \n",
       "L 316.410793 253.900556 \n",
       "L 317.351821 258.407639 \n",
       "L 318.292848 256.70437 \n",
       "L 319.233876 255.582591 \n",
       "L 320.174904 257.688785 \n",
       "L 321.115931 257.437688 \n",
       "L 322.056959 254.025486 \n",
       "L 322.997987 254.350388 \n",
       "L 323.939014 257.444481 \n",
       "L 325.82107 255.275704 \n",
       "L 326.762097 257.880324 \n",
       "L 327.703125 257.442426 \n",
       "L 328.644153 255.069056 \n",
       "L 329.58518 254.260294 \n",
       "L 330.526208 258.364764 \n",
       "L 331.467236 257.39282 \n",
       "L 332.408263 256.188544 \n",
       "L 333.349291 257.451029 \n",
       "L 334.290319 256.917066 \n",
       "L 335.231346 256.178621 \n",
       "L 336.172374 257.856601 \n",
       "L 337.113402 257.484515 \n",
       "L 338.054429 255.567074 \n",
       "L 338.995457 254.60554 \n",
       "L 339.936485 256.353641 \n",
       "L 340.877512 255.635004 \n",
       "L 341.81854 254.458124 \n",
       "L 342.759568 256.771594 \n",
       "L 343.700595 254.277542 \n",
       "L 344.641623 254.653062 \n",
       "L 345.582651 251.519851 \n",
       "L 346.523678 255.200246 \n",
       "L 348.405734 253.060595 \n",
       "L 349.346761 256.76209 \n",
       "L 350.287789 255.403931 \n",
       "L 351.228817 254.594995 \n",
       "L 352.169844 251.925199 \n",
       "L 353.110872 256.358937 \n",
       "L 354.0519 255.043338 \n",
       "L 354.992927 254.49646 \n",
       "L 355.933955 256.381141 \n",
       "L 356.874983 256.316062 \n",
       "L 357.81601 254.854559 \n",
       "L 358.757038 253.118861 \n",
       "L 359.698066 256.291414 \n",
       "L 360.639093 254.645116 \n",
       "L 361.580121 253.994314 \n",
       "L 362.521149 256.192663 \n",
       "L 363.462176 256.367846 \n",
       "L 364.403204 253.597483 \n",
       "L 365.344232 252.696696 \n",
       "L 366.285259 254.822783 \n",
       "L 367.226287 253.12797 \n",
       "L 368.167315 252.216313 \n",
       "L 369.108342 254.865108 \n",
       "L 370.04937 254.635501 \n",
       "L 370.990398 252.625172 \n",
       "L 370.990398 252.625172 \n",
       "\" clip-path=\"url(#p1f3d62b452)\" style=\"fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_3\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 30.103125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_4\">\n",
       "    <path d=\"M 387.223125 273.312 \n",
       "L 387.223125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_5\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 387.223125 273.312 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_6\">\n",
       "    <path d=\"M 30.103125 7.2 \n",
       "L 387.223125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "  </g>\n",
       " </g>\n",
       " <defs>\n",
       "  <clipPath id=\"p1f3d62b452\">\n",
       "   <rect x=\"30.103125\" y=\"7.2\" width=\"357.12\" height=\"266.112\"/>\n",
       "  </clipPath>\n",
       " </defs>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot([i[\"step\"] for i in record[\"train\"][::50]], [i[\"loss\"] for i in record[\"train\"][::50]], label=\"train\")\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 推理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d4f98bb9e74b407e8819721d220d2e32",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1000 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All: what's the news?\n",
      "\n",
      "Second Messenger:\n",
      "Sir, you shall never go to-day?\n",
      "\n",
      "PETRUCHIO:\n",
      "Petruchio is chief to protector?\n",
      "\n",
      "ELBOW:\n",
      "I pray you hear it, and will say it is too much.\n",
      "\n",
      "ANGELO:\n",
      "No marry with a valour with a gentlern blisters\n",
      "Of mortals than a party to the good,\n",
      "And not be too sure nor privileges;\n",
      "Or, if not, unless you were so contented\n",
      "That he is based, in quiet. Nie, charge thee, fellow,\n",
      "He caper in blood, and blows the world be full.\n",
      "\n",
      "GONZALO:\n",
      "Not a word, a word.\n",
      "\n",
      "MENENIUS:\n",
      "Why, then I'll try what I am, and there an end.\n",
      "\n",
      "BAPTISTA:\n",
      "Why, tell me, is nothing finding to you.\n",
      "\n",
      "PETRUCHIO:\n",
      "To her, farewell.\n",
      "\n",
      "GREMIO:\n",
      "And so in what?\n",
      "\n",
      "HERMIONE:\n",
      "Nay, come again.\n",
      "\n",
      "DUKE VINCENTIO:\n",
      "And you, good lord; a man't must die.\n",
      "\n",
      "ISABELLA:\n",
      "What is your will?\n",
      "\n",
      "DUKE VINCENTIO:\n",
      "Bold power that I may say indeed\n",
      "Than in the fore-appreasers.\n",
      "\n",
      "CORIOLANUS:\n",
      "Wiffer much, being madam, and you must say.\n",
      "\n",
      "LORD BERKELEY:\n",
      "Mistake me not; I speak with him to-day.\n",
      "\n",
      "BENVOLIO:\n",
      "Would they have made with you so soft than a"
     ]
    }
   ],
   "source": [
    "def generate_text(model, start_string, max_len=1000, temperature=1.0, stream=True):\n",
    "    input_eval = torch.Tensor([char2idx[char] for char in start_string]).to(dtype=torch.int64, device=device).reshape(1, -1)\n",
    "    hidden = None\n",
    "    text_generated = []\n",
    "    model.eval()\n",
    "    pbar = tqdm(range(max_len))\n",
    "    print(start_string, end=\"\")\n",
    "    with torch.no_grad():\n",
    "        for i in pbar:\n",
    "            logits, hidden = model(input_eval, hidden=hidden)\n",
    "            # 温度采样\n",
    "            logits = logits[0, -1, :] / temperature\n",
    "            # using multinomial to sampling\n",
    "            probs = F.softmax(logits, dim=-1)\n",
    "            idx = torch.multinomial(probs, 1).item()\n",
    "            input_eval = torch.Tensor([idx]).to(dtype=torch.int64, device=device).reshape(1, -1)\n",
    "            text_generated.append(idx)\n",
    "            if stream:\n",
    "                print(idx2char[idx], end=\"\", flush=True)\n",
    "    return \"\".join([idx2char[i] for i in text_generated])\n",
    "\n",
    "\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/text_generation_lstm/best.ckpt\", map_location=\"cpu\"))\n",
    "start_string = \"All: \"\n",
    "res = generate_text(model, start_string, max_len=1000, temperature=0.5, stream=True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
